package com.cybertron.am.wordpress.job.parser;

import com.cybertron.am.wordpress.domain.CrawlCategory;
import com.cybertron.am.wordpress.domain.CrawlProduct;
import com.cybertron.am.wordpress.job.CrawlResult;
import com.cybertron.am.wordpress.job.Parser;
import com.cybertron.am.wordpress.util.SysUtil;
import com.cybertron.am.wordpress.util.UrlUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.ne.boot.common.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Component;
import us.codecraft.xsoup.XElements;
import us.codecraft.xsoup.Xsoup;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component
@Slf4j
public class Mercyabounding implements Parser {

    @Override
    public String domain() {
        return "mercyabounding.net";
    }

    @Override
    public List<CrawlCategory> getCategory(CrawlResult crawlResult) {
        XElements elements = Xsoup.select(crawlResult.getDocument(), "//li[@class='x-menu--level-2--link']");
        List<CrawlCategory> categories = new ArrayList<>();
        for (Element element : elements.getElements()) {
            String title = Xsoup.select(element, "/a/html()").get();
            String id = DigestUtils.md5Hex(title);
            categories.add(CrawlCategory.builder()
                    .id(id)
                    .title(title)
                    .build());
            Elements childEls = Xsoup.select(element, "/ul//a").getElements();
            for (Element childEl : childEls) {
                String childUrl = UrlUtil.resolveUrl(crawlResult.getUrl(), Xsoup.select(childEl, "/@href").get());
                categories.add(CrawlCategory.builder()
                        .id(DigestUtils.md5Hex(childUrl))
                        .title(Xsoup.select(childEl, "/html()").get())
                        .url(childUrl)
                        .parentId(id)
                        .build());
            }
        }
        return categories;
    }

    @Override
    public List<String> getProductUrl(CrawlResult crawlResult) {
        List<String> urls = Xsoup.select(crawlResult.getDocument(), "//div[@class='product--root']/a/@href").list();
        if (CollectionUtils.isEmpty(urls)) {
            return null;
        }
        return urls.stream()
                .map(v -> UrlUtil.resolveUrl(crawlResult.getUrl(), "/products/" + StringUtils.substringAfterLast(v, "/products/")))
                .collect(Collectors.toList());
    }

    @Override
    public List<String> getNextPageUrl(CrawlResult crawlResult) {
        List<String> urls = Xsoup.select(crawlResult.getDocument(), "//div[@class='pagination--root']//a[@class='pagination--link']/@href").list();
        if (CollectionUtils.isEmpty(urls)) {
            return null;
        }
        return urls.stream()
                .map(v -> UrlUtil.resolveUrl(crawlResult.getUrl(), v))
                .collect(Collectors.toList());
    }

    @Override
    public CrawlProduct getProduct(CrawlResult crawlResult) {
        List<String> images = Xsoup.select(crawlResult.getDocument(), "//div[@class='image--root']//noscript//img/@src").list();
        List<String> options = Xsoup.select(crawlResult.getDocument(), "//label[@class='disclosure--label']//html()").list();
        String variantJson = StringUtils.substringBetween(crawlResult.getHtml(), "window.NibbleShopifyData.products =", "</script>");
        variantJson = "[{" + StringUtils.substringBetween(variantJson, "\"variants\":[{", ",\"images\"");
        List<Map<String, Object>> variantMaps = JsonUtil.readValue(variantJson, new TypeReference<List<Map<String, Object>>>() {
        });
        List<CrawlProduct.CrawlVariant> variants = CollectionUtils.isEmpty(variantMaps) ? null : variantMaps.stream()
                .map(v -> {
                    List<String> variantOptions = SysUtil.mvelEval("options", v, List.class);
                    String variantImage = SysUtil.mvelEval("featured_image.src", v, String.class);
                    return CrawlProduct.CrawlVariant.builder()
                            .title(MapUtils.getString(v, "title"))
                            .price(String.valueOf(MapUtils.getInteger(v, "price", 200) / 100))
                            .image(StringUtils.isBlank(variantImage) ? null : "https:" + variantImage)
                            .options(CollectionUtils.isEmpty(variantOptions) ? null : variantOptions.toArray(new String[]{}))
                            .build();
                })
                .collect(Collectors.toList());
        return CrawlProduct.builder()
                .id(DigestUtils.md5Hex(crawlResult.getUrl()))
                .url(crawlResult.getUrl())
                .title(Xsoup.select(crawlResult.getDocument(), "//h1[@class*='product-page--title']/html()").get())
                .description(Xsoup.select(crawlResult.getDocument(), "//div[@class*='product-page--description']/html()").get())
                .price(Xsoup.select(crawlResult.getDocument(), "//span[@class*='money']/regex('\\d+(,?\\d+)*(\\.?\\d+)*',0)").get())
                .images(CollectionUtils.isNotEmpty(images) ? images.stream().map(v -> "https:" + v).toArray(String[]::new) : null)
                .options(CollectionUtils.isNotEmpty(options) ? options.toArray(new String[]{}) : null)
                .variants(CollectionUtils.isNotEmpty(variants) ? variants.toArray(new CrawlProduct.CrawlVariant[]{}) : null)
                .build();
    }
}
